import Axios, { AxiosInstance, AxiosRequestConfig } from 'axios'
import { RequestMethods, AxiosHttpResponse, AxiosHttpRequestConfig } from './types.d'
import qs from 'qs'
import { storeToRefs } from 'pinia'
import NProgress from '../progress'
import router from '@/router'
import { user } from '@/api/user'
import { startLoading, endLoading } from './loading'
import { judgeRending, removePending } from './cancelToken'
import { httpErrorStatusHandler } from './errorCode'
import { transformI18n } from '@/plugins/i18n'
import { loadEnv } from '^/index'
import useLogout from '@/hooks/useLogout'
import { useUserInfoStoreWithOut } from '@/store/storage/userInfoStore'
import { useSystemConfigStoreWithOut } from '@/store/storage/systemConfigStore'
const { VITE_BASE_API_PATH, VITE_PROXY_API_PATH } = loadEnv()
const userInfoStore = useUserInfoStoreWithOut()
const systemConfigStore = useSystemConfigStoreWithOut()
// 详细配置可参考：www.axios-js.com/zh-cn/docs/#axios-request-config-1
const defaultConfig: AxiosRequestConfig = {
  baseURL: VITE_PROXY_API_PATH && VITE_PROXY_API_PATH !== '' ? VITE_PROXY_API_PATH : VITE_BASE_API_PATH,
  timeout: 50000,
  headers: {
    Accept: 'application/json, text/plain, */*',
    'Content-Type': 'application/json',
    'X-Requested-With': 'XMLHttpRequest'
  },
  // get请求中数组格式的参数进行序列化
  paramsSerializer: (params) => qs.stringify(params, { indices: false })
}

// 是否正在刷新的标记
let isRefreshing = false
// 重试队列，每一项将是一个待执行的函数形式
let requests: any = []

// 超时请求个数记录，如有多个异步超时请求记录，只展示一个超时提示
let timeoutCount = 0

export const initRequest = () => {
  timeoutCount = 0
}

class AxiosHttp {
  constructor() {
    this.httpInterceptorsRequest()
    this.httpInterceptorsResponse()
  }
  // 初始化配置对象
  private static initConfig: AxiosHttpRequestConfig = {}
  // 保存当前Axios实例对象
  private static axiosInstance: AxiosInstance = Axios.create(defaultConfig)
  // 设置请求前的回调
  private beforeRequestCallback: AxiosHttpRequestConfig['beforeRequestCallback'] = undefined
  // 设置响应前的回调
  private beforeResponseCallback: AxiosHttpRequestConfig['beforeResponseCallback'] = undefined

  private static transformConfigByMethod(params: any, config: AxiosHttpRequestConfig): AxiosHttpRequestConfig {
    const { method } = config
    const props = ['delete', 'get', 'head', 'options'].includes(method?.toLocaleLowerCase()) ? 'params' : 'data'
    return {
      ...config,
      [props]: params
    }
  }
  // 请求拦截
  private httpInterceptorsRequest(): void {
    const { systemConfig } = storeToRefs(systemConfigStore)
    const { userInfo } = storeToRefs(userInfoStore)
    AxiosHttp.axiosInstance.interceptors.request.use(
      (config: AxiosHttpRequestConfig) => {
        const $config = config
        // 是否使用mock模拟的后端接口
        if ($config.config && $config.config.mockEnable) {
          $config.baseURL = ''
        }
        // 自定义参数字段不存在，或者自定义参数存在，但是取消重复请求功能未被禁用
        if (!$config.config || ($config.config && !$config.config.cancelRepeatDisabled)) {
          judgeRending($config)
        }
        if (systemConfig.value && systemConfig.value.isLoadingEnable && $config.config.showLoading) {
          startLoading($config.config.loadingOptions)
        }
        // 开启进度条动画
        if (systemConfig.value && systemConfig.value.isProgressEnable) {
          NProgress.start()
        }
        // 优先判断请求是否传入了自定义配置的回调函数，否则执行初始化设置等回调
        if (typeof config.beforeRequestCallback === 'function') {
          config.beforeRequestCallback($config)
          this.beforeRequestCallback = undefined
          return $config
        }
        // 判断初始化状态中有没有回调函数，没有的话
        if (AxiosHttp.initConfig.beforeRequestCallback) {
          AxiosHttp.initConfig.beforeRequestCallback($config)
          return $config
        }
        // 确保config.url永远不会是undefined，增加断言
        if (!config.url) {
          config.url = ''
        }
        // 登录接口和刷新token接口不需要在headers中回传token，在走刷新token接口走到这里后，需要拦截，否则继续往下走，刷新token接口这里会陷入死循环
        if (config.url.indexOf('/refreshToken') >= 0 || config.url.indexOf('/Login') >= 0) {
          return $config
        }
        // 判断token是否存在
        if (userInfo.value && userInfo.value.accessToken) {
          // 确保config.headers永远不会是undefined，增加断言
          if (!config.headers) {
            config.headers = {}
          }
          config.headers['Authorization'] = 'Bearer ' + userInfo.value.accessToken
          return $config
        } else {
          return $config
        }
      },
      (error) => {
        // 当前请求出错，当前请求加1的loading也需要减掉
        if (systemConfig.value && systemConfig.value.isLoadingEnable && error.config.config.showLoading) {
          endLoading()
        }
        return Promise.reject(error)
      }
    )
  }

  // 响应拦截
  private httpInterceptorsResponse(): void {
    const instance = AxiosHttp.axiosInstance
    const { systemConfig } = storeToRefs(systemConfigStore)
    const { userInfo } = storeToRefs(userInfoStore)
    instance.interceptors.response.use(
      (response: AxiosHttpResponse) => {
        const $config = response.config
        // 自定义参数字段不存在，或者自定义参数存在，但是取消重复请求功能未被禁用
        if (!$config.config || ($config.config && !$config.config.cancelRepeatDisabled)) {
          // 增加延时，相同请求再完成后，不得在短时间内重复请求
          setTimeout(() => {
            removePending($config)
          }, 500)
        }
        // 关闭进度条动画
        if (systemConfig.value && systemConfig.value.isProgressEnable) {
          NProgress.done()
        }
        // if (response.data.status === true) {
        //   // 优先判断请求是否传入了自定义配置的回调函数，否则执行初始化设置等回调
        //   if (typeof $config.beforeResponseCallback === 'function') {
        //     $config.beforeResponseCallback(response)
        //     this.beforeResponseCallback = undefined
        //   }
        //   if (AxiosHttp.initConfig.beforeResponseCallback) {
        //     AxiosHttp.initConfig.beforeResponseCallback(response)
        //   }
        //   if (systemConfig.value && systemConfig.value.isLoadingEnable && response.config.config.showLoading) {
        //     endLoading()
        //   }
        //   return response.data
        // } else {
        //   if (systemConfig.value && systemConfig.value.isLoadingEnable && response.config.config.showLoading) {
        //     endLoading()
        //   }
        //   const { Logout } = useLogout(router)
        //   if (response.data.status === 201) {
        //     ElNotification({
        //       title: transformI18n('errors.error', true),
        //       message: transformI18n('errors.errorLoginTimeOut', true),
        //       type: 'error'
        //     })
        //     // 清除缓存中的用户信息
        //     Logout()
        //   } else if (response.data.status === 202) {
        //     ElNotification({
        //       title: transformI18n('errors.error', true),
        //       message: transformI18n('errors.errorCode202', true),
        //       type: 'error'
        //     })
        //     router.push(`/Exception/403`)
        //   } else {
        //     ElNotification({
        //       title: transformI18n('errors.error', true),
        //       message: response.data.info,
        //       type: 'error',
        //       duration: 0
        //     })
        //     return null
        //   }
        // }
        if (response.data.code === 200) {
          if (response.data.status) {
            // 优先判断请求是否传入了自定义配置的回调函数，否则执行初始化设置等回调
            if (typeof $config.beforeResponseCallback === 'function') {
              $config.beforeResponseCallback(response)
              this.beforeResponseCallback = undefined
            }
            if (AxiosHttp.initConfig.beforeResponseCallback) {
              AxiosHttp.initConfig.beforeResponseCallback(response)
            }
            if (systemConfig.value && systemConfig.value.isLoadingEnable && response.config.config.showLoading) {
              endLoading()
            }
            return response.data
          } else {
            if (systemConfig.value && systemConfig.value.isLoadingEnable && response.config.config.showLoading) {
              endLoading()
            }
            ElNotification({
              title: transformI18n('errors.error', true),
              message: response.data.info,
              type: 'error',
              duration: 0
            })
            return null
          }
        } else {
          if (systemConfig.value && systemConfig.value.isLoadingEnable && response.config.config.showLoading) {
            endLoading()
          }
          const { Logout } = useLogout(router)
          if (response.data.code === 201002) {
            if (timeoutCount === 0) {
              timeoutCount += 1
              ElNotification({
                title: transformI18n('errors.error', true),
                message: transformI18n('errors.errorLoginTimeOut', true),
                type: 'error'
              })
              // 清除缓存中的用户信息
              Logout()
            }
          } else if (response.data.code === 201004) {
            if (userInfo.value) {
              if (!isRefreshing) {
                isRefreshing = true
                return user
                  .refreshToken({ refreshToken: userInfo.value.refreshToken }, { config: { mockEnable: true } })
                  .then((res: any) => {
                    if (res.status) {
                      userInfo.value.accessToken = res.data.accessToken
                      userInfo.value.refreshToken = res.data.refreshToken
                      userInfoStore.setUserInfoCache()
                      // 确保config.headers永远不会是undefined，增加断言
                      if (!$config.headers) {
                        $config.headers = {}
                      }
                      $config.headers['Authorization'] = 'Bearer ' + res.data.accessToken
                      $config.baseURL = ''
                      // 已经刷新了token，将所有队列中的请求进行重试
                      requests.forEach((callback: any) => callback(userInfo.value.accessToken))
                      requests = []
                      return instance($config)
                    }
                  })
                  .catch(() => {
                    // 清除缓存中的用户信息
                    Logout()
                  })
                  .finally(() => {
                    isRefreshing = false
                  })
              } else {
                // 正在刷新token，将返回一个未执行resolve的promise
                return new Promise((resolve) => {
                  // 将resolve放进队列，用一个函数形式来保存，等token刷新后直接执行
                  requests.push((accessToken: string) => {
                    // 响应以后，请求接口的$config.url已经包含了baseURL部分，这里需要将baseURL清空，防止再次请求时，再次组装，导致url错误
                    $config.baseURL = ''
                    // 确保config.headers永远不会是undefined，增加断言
                    if (!$config.headers) {
                      $config.headers = {}
                    }
                    $config.headers['Authorization'] = 'Bearer ' + accessToken
                    resolve(instance($config))
                  })
                })
              }
            }
          } else {
            ElNotification({
              title: transformI18n('errors.error', true),
              message: response.data.info,
              type: 'error',
              duration: 0
            })
            return null
          }
        }
      },
      (error) => {
        // 关闭进度条动画
        if (systemConfig.value && systemConfig.value.isProgressEnable) {
          NProgress.done()
        }
        if (Axios.isCancel(error)) {
          console.log(error.message)
          return false
        } else {
          httpErrorStatusHandler(error)
          if (systemConfig.value && systemConfig.value.isLoadingEnable && error.config && (!error.config.config || (error.config.config && error.config.config.showLoading))) {
            endLoading()
          }
          // 自定义参数字段不存在，或者自定义参数存在，但是取消重复请求功能未被禁用
          if (error.config && (!error.config.config || (error.config.config && !error.config.config.cancelRepeatDisabled))) {
            // 增加延时，相同请求再完成后，不得在短时间内重复请求
            setTimeout(() => {
              removePending(error.config)
            }, 500)
          }
          // 所有的响应异常 区分来源为取消请求/非取消请求
          return Promise.reject(error)
        }
      }
    )
  }

  // 通用请求工具函数
  public request<T>(method: RequestMethods, url: string, param?: AxiosRequestConfig, axiosConfig?: AxiosHttpRequestConfig): Promise<T> {
    // post与get请求的参数需要用不同的key去接收，这里需要做判断，在请求中get的参数是params接收的，post的参数是data接收的
    const config = AxiosHttp.transformConfigByMethod(param, {
      method,
      url,
      ...axiosConfig
    } as AxiosHttpRequestConfig)
    // 如果没有自定义的loading配置，需要给默认值，默认值就是启用全局loading
    if (config.config === undefined) {
      config.config = {
        showLoading: true
      }
    } else {
      // 防止定义了config，但未定义showLoading
      if (config.config.showLoading === undefined) {
        config.config.showLoading = true
      }
    }
    // 单独处理自定义请求/响应回调
    if (axiosConfig?.beforeRequestCallback) {
      this.beforeRequestCallback = axiosConfig.beforeRequestCallback
    }
    if (axiosConfig?.beforeResponseCallback) {
      this.beforeResponseCallback = axiosConfig.beforeResponseCallback
    }
    // 单独处理自定义请求/响应回掉
    return new Promise((resolve, reject) => {
      AxiosHttp.axiosInstance
        .request(config)
        .then((response: any) => {
          resolve(response)
        })
        .catch((error) => {
          reject(error)
        })
    })
  }

  // 单独抽离的post工具函数
  public post<T>(url: string, params?: T, config?: AxiosHttpRequestConfig): Promise<T> {
    return this.request<T>('post', url, params, config)
  }

  // 单独抽离的get工具函数
  public get<T>(url: string, params?: T, config?: AxiosHttpRequestConfig): Promise<T> {
    return this.request<T>('get', url, params, config)
  }
}

export const http = new AxiosHttp()
